Python์ ์ถ์ ๊ธฐ๋ณธ ํด๋์ค(ABC)์ ๊ฐ๋ ฅํจ์ ํ์ฉํ์ธ์. ํ๋กํ ์ฝ ๊ธฐ๋ฐ ๊ตฌ์กฐ์ ํ์ดํ๊ณผ ๊ณต์ ์ธํฐํ์ด์ค ๋์์ธ์ ์ค์ํ ์ฐจ์ด์ ์ ์์๋ณด์ธ์.
Python ์ถ์ ๊ธฐ๋ณธ ํด๋์ค: ํ๋กํ ์ฝ ๊ตฌํ vs. ์ธํฐํ์ด์ค ๋์์ธ ๋ง์คํฐํ๊ธฐ
์ํํธ์จ์ด ๊ฐ๋ฐ์ ์ธ๊ณ์์ ๊ฐ๋ ฅํ๊ณ ์ ์ง๋ณด์ ๊ฐ๋ฅํ๋ฉฐ ํ์ฅ ๊ฐ๋ฅํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ๋ ๊ฒ์ด ๊ถ๊ทน์ ์ธ ๋ชฉํ์ ๋๋ค. ํ๋ก์ ํธ๊ฐ ๋ช ๊ฐ์ ์คํฌ๋ฆฝํธ์์ ๊ตญ์ ํ์ด ๊ด๋ฆฌํ๋ ๋ณต์กํ ์์คํ ์ผ๋ก ์ฑ์ฅํจ์ ๋ฐ๋ผ ๋ช ํํ ๊ตฌ์กฐ์ ์์ธก ๊ฐ๋ฅํ ๊ณ์ฝ์ ํ์์ฑ์ด ๊ฐ์ฅ ์ค์ํด์ง๋๋ค. ์๋ก ๋ค๋ฅธ ์๊ฐ๋์ ๊ฑธ์ณ ๋ค๋ฅธ ๊ฐ๋ฐ์๊ฐ ์์ฑํ์ ์ ์๋ ๋ค์ํ ๊ตฌ์ฑ ์์๊ฐ ์ด๋ป๊ฒ ์ํํ๊ณ ์์ ์ ์ผ๋ก ์ํธ ์์ฉํ ์ ์๋๋ก ํ ์ ์์๊น์? ๋ต์ ์ถ์ํ์ ์์น์ ์์ต๋๋ค.
Python์ ๋์ ์ธ ํน์ฑ์ ๊ฐ์ง๊ณ ์์ผ๋ฉฐ, ์ถ์ํ๋ฅผ ์ํ ์ ๋ช ํ ์ฒ ํ์ธ "๋ ํ์ดํ"์ ๊ฐ์ง๊ณ ์์ต๋๋ค. ๊ฐ์ฒด๊ฐ ์ค๋ฆฌ์ฒ๋ผ ๊ฑท๊ณ ์ค๋ฆฌ์ฒ๋ผ ๊ฝฅ๊ฝฅ๊ฑฐ๋ฆฐ๋ค๋ฉด, ์ฐ๋ฆฌ๋ ๊ทธ๊ฒ์ ์ค๋ฆฌ๋ก ๋ํฉ๋๋ค. ์ด๋ฌํ ์ ์ฐ์ฑ์ Python์ ๊ฐ์ฅ ํฐ ๊ฐ์ ์ค ํ๋๋ก, ๋น ๋ฅธ ๊ฐ๋ฐ๊ณผ ๊น๋ํ๊ณ ์ฝ๊ธฐ ์ฌ์ด ์ฝ๋๋ฅผ ์ด์งํฉ๋๋ค. ๊ทธ๋ฌ๋ ๋๊ท๋ชจ ์ ํ๋ฆฌ์ผ์ด์ ์์๋ ์๋ฌต์ ์ธ ๊ณ์ฝ์๋ง ์์กดํ๋ฉด ๋ฏธ๋ฌํ ๋ฒ๊ทธ์ ์ ์ง๋ณด์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค. "์ค๋ฆฌ"๊ฐ ์์์น ๋ชปํ๊ฒ ๋ ์ง ๋ชปํ๋ฉด ์ด๋ป๊ฒ ๋ ๊น์? ์ด๋ Python์ ์ถ์ ๊ธฐ๋ณธ ํด๋์ค(ABC)๊ฐ ๋ฑ์ฅํ์ฌ Python์ ๋์ ์ธ ์ ์ ์ ํฌ์ํ์ง ์๊ณ ๋ ๊ณต์ ๊ณ์ฝ์ ์์ฑํ๋ ๊ฐ๋ ฅํ ๋ฉ์ปค๋์ฆ์ ์ ๊ณตํฉ๋๋ค.
ํ์ง๋ง ์ฌ๊ธฐ์ ์ค์ํ๊ณ ์ข ์ข ์คํด๋๋ ๊ตฌ๋ถ์ด ์์ต๋๋ค. Python์ ABC๋ ๋ง๋ฅ ๋๊ตฌ๊ฐ ์๋๋๋ค. ์ด๋ค์ ์ํํธ์จ์ด ๋์์ธ์ ๋ ๊ฐ์ง ๋๋ ทํ๊ณ ๊ฐ๋ ฅํ ์ฒ ํ์ ์ ๊ณตํฉ๋๋ค. ์ฆ, ์์์ ์๊ตฌํ๋ ๋ช ์์ ์ด๊ณ ๊ณต์์ ์ธ ์ธํฐํ์ด์ค๋ฅผ ์์ฑํ๊ณ , ๊ธฐ๋ฅ์ ํ์ธํ๋ ์ ์ฐํ ํ๋กํ ์ฝ์ ์ ์ํ๋ ๊ฒ์ ๋๋ค. ์ด ๋ ๊ฐ์ง ์ ๊ทผ ๋ฐฉ์, ์ฆ ์ธํฐํ์ด์ค ๋์์ธ๊ณผ ํ๋กํ ์ฝ ๊ตฌํ์ ์ฐจ์ด๋ฅผ ์ดํดํ๋ ๊ฒ์ด Python์์ ๊ฐ์ฒด ์งํฅ ๋์์ธ์ ์ ์ฌ๋ ฅ์ ์ต๋ํ ๋ฐํํ๊ณ ์ ์ฐํ๊ณ ์์ ํ ์ฝ๋๋ฅผ ์์ฑํ๋ ์ด์ ์ ๋๋ค. ์ด ๊ฐ์ด๋์์๋ ๋ ๊ฐ์ง ์ฒ ํ์ ํ๊ตฌํ๊ณ , ๊ธ๋ก๋ฒ ์ํํธ์จ์ด ํ๋ก์ ํธ์์ ๊ฐ ์ ๊ทผ ๋ฐฉ์์ ์ฌ์ฉํ ๋์ ๋ํ ์ค์ฉ์ ์ธ ์์ ์ ๋ช ํํ ์ง์นจ์ ์ ๊ณตํฉ๋๋ค.
ํ์์ ๋ํ ์ฐธ๊ณ ์ฌํญ: ํน์ ํ์ ์ ์ฝ ์กฐ๊ฑด์ ์ค์ํ๊ธฐ ์ํด ์ด ๊ธฐ์ฌ์ ์ฝ๋ ์์ ๋ ์ผ๋ฐ ํ ์คํธ ํ๊ทธ ๋ด์์ ๋ณผ๋์ฒด ๋ฐ ์ดํค๋ฆญ์ฒด ์คํ์ผ์ ์ฌ์ฉํ์ฌ ์ ๊ณต๋ฉ๋๋ค. ๊ฐ๋ ์ฑ์ ์ํด ํธ์ง๊ธฐ์ ๋ณต์ฌํ์ฌ ๋ถ์ฌ๋ฃ๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค.
๊ธฐ๋ฐ: ์ถ์ ๊ธฐ๋ณธ ํด๋์ค๋ ์ ํํ ๋ฌด์์ธ๊ฐ?
๋ ๊ฐ์ง ๋์์ธ ์ฒ ํ์ ์์ธํ ์ดํด๋ณด๊ธฐ ์ ์ ๊ฒฌ๊ณ ํ ๊ธฐ๋ฐ์ ๊ตฌ์ถํด ๋ด ์๋ค. ์ถ์ ๊ธฐ๋ณธ ํด๋์ค๋ ๋ฌด์์ธ๊ฐ์? ๊ธฐ๋ณธ์ ์ผ๋ก ABC๋ ๋ค๋ฅธ ํด๋์ค๋ฅผ ์ํ ์ฒญ์ฌ์ง์ ๋๋ค. ์ด๋ ์ค์ํ๋ ๋ชจ๋ ํ์ ํด๋์ค๊ฐ ๊ตฌํํด์ผ ํ๋ ๋ฉ์๋ ๋ฐ ์์ฑ ์งํฉ์ ์ ์ํฉ๋๋ค. "์ด ๊ฐ์กฑ์ ์ผ๋ถ๋ผ๊ณ ์ฃผ์ฅํ๋ ๋ชจ๋ ํด๋์ค๋ ์ด๋ฌํ ํน์ ๊ธฐ๋ฅ์ ๊ฐ์ ธ์ผ ํ๋ค"๊ณ ๋งํ๋ ๋ฐฉ๋ฒ์ ๋๋ค.
Python์ ๋ด์ฅ `abc` ๋ชจ๋์ ABC๋ฅผ ์์ฑํ๋ ๋๊ตฌ๋ฅผ ์ ๊ณตํฉ๋๋ค. ๋ ๊ฐ์ง ์ฃผ์ ๊ตฌ์ฑ ์์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- `ABC`: ABC๋ฅผ ์์ฑํ๊ธฐ ์ํ ๋ฉํํด๋์ค๋ก ์ฌ์ฉ๋๋ ๋์ฐ๋ฏธ ํด๋์ค์
๋๋ค. ์ต์ Python(3.4+)์์๋ ๋จ์ํ
abc.ABC
๋ฅผ ์์ํ๋ฉด ๋ฉ๋๋ค. - `@abstractmethod`: ๋ฉ์๋๋ฅผ ์ถ์์ผ๋ก ํ์ํ๋ ๋ฐ ์ฌ์ฉ๋๋ ๋ฐ์ฝ๋ ์ดํฐ์ ๋๋ค. ABC์ ๋ชจ๋ ํ์ ํด๋์ค๋ ์ด๋ฌํ ๋ฉ์๋๋ฅผ ๊ตฌํํด์ผ ํฉ๋๋ค.
ABC๋ฅผ ์ ์ดํ๋ ๋ ๊ฐ์ง ๊ธฐ๋ณธ ๊ท์น์ด ์์ต๋๋ค.
- ๊ตฌํ๋์ง ์์ ์ถ์ ๋ฉ์๋๊ฐ ์๋ ABC์ ์ธ์คํด์ค๋ฅผ ์์ฑํ ์ ์์ต๋๋ค. ์ด๋ ํ ํ๋ฆฟ์ด๋ฉฐ ์์ฑ๋ ์ ํ์ด ์๋๋๋ค.
- ๋ชจ๋ ๊ตฌ์ฒด์ ์ธ ํ์ ํด๋์ค๋ ์์๋ ๋ชจ๋ ์ถ์ ๋ฉ์๋๋ฅผ ๊ตฌํํด์ผ ํฉ๋๋ค. ๊ทธ๋ ๊ฒ ํ์ง ๋ชปํ๋ฉด ํด๋น ํด๋์ค๋ ์ถ์ ํด๋์ค๊ฐ ๋๋ฉฐ ์ธ์คํด์ค๋ฅผ ์์ฑํ ์ ์์ต๋๋ค.
๊ณ ์ ์ ์ธ ์์ ์ธ ๋ฏธ๋์ด ํ์ผ ์ฒ๋ฆฌ ์์คํ ์ ํตํด ์ด๋ฅผ ํ์ธํด ๋ด ์๋ค.
์์ : ๊ฐ๋จํ MediaFile ABC
๋ค์ํ ์ ํ์ ๋ฏธ๋์ด๋ฅผ ์ฒ๋ฆฌํด์ผ ํ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ๋ค๊ณ ๊ฐ์ ํด ๋ด ์๋ค. ๋ชจ๋ ๋ฏธ๋์ด ํ์ผ์ ํ์์ ๊ด๊ณ์์ด ์ฌ์ ๊ฐ๋ฅํด์ผ ํ๋ฉฐ ๋ฉํ๋ฐ์ดํฐ๊ฐ ์์ด์ผ ํฉ๋๋ค. ABC๋ก ์ด ๊ณ์ฝ์ ์ ์ํ ์ ์์ต๋๋ค.
import abc
class MediaFile(abc.ABC):
def __init__(self, filepath: str):
self.filepath = filepath
print(f"Base init for {self.filepath}")
@abc.abstractmethod
def play(self) -> None:
"""Play the media file."""
raise NotImplementedError
@abc.abstractmethod
def get_metadata(self) -> dict:
"""Return a dictionary of media metadata."""
raise NotImplementedError
MediaFile
์ ์ธ์คํด์ค๋ฅผ ์ง์ ์์ฑํ๋ ค๊ณ ํ๋ฉด Python์์ ์ค์ง๋ฉ๋๋ค.
# TypeError๊ฐ ๋ฐ์ํฉ๋๋ค
# media = MediaFile("path/to/somefile.txt")
# TypeError: Can't instantiate abstract class MediaFile with abstract methods get_metadata, play
์ด ์ฒญ์ฌ์ง์ ์ฌ์ฉํ๋ ค๋ฉด play()
๋ฐ get_metadata()
์ ๋ํ ๊ตฌํ์ ์ ๊ณตํ๋ ๊ตฌ์ฒด์ ์ธ ํ์ ํด๋์ค๋ฅผ ๋ง๋ค์ด์ผ ํฉ๋๋ค.
class AudioFile(MediaFile):
def play(self) -> None:
print(f"Playing audio from {self.filepath}...")
def get_metadata(self) -> dict:
return {"codec": "mp3", "duration_seconds": 180}
class VideoFile(MediaFile):
def play(self) -> None:
print(f"Playing video from {self.filepath}...")
def get_metadata(self) -> dict:
return {"codec": "h264", "resolution": "1920x1080"}
์ด์ MediaFile
์ ์ํด ์ ์๋ ๊ณ์ฝ์ ์ถฉ์กฑํ๋ฏ๋ก AudioFile
๋ฐ VideoFile
์ ์ธ์คํด์ค๋ฅผ ์์ฑํ ์ ์์ต๋๋ค. ์ด๊ฒ์ด ABC์ ๊ธฐ๋ณธ ๋ฉ์ปค๋์ฆ์
๋๋ค. ๊ทธ๋ฌ๋ ์ง์ ํ ํ์ ์ด ๋ฉ์ปค๋์ฆ์ *์ฌ์ฉํ๋ ๋ฐฉ๋ฒ*์์ ๋์ต๋๋ค.
์ฒซ ๋ฒ์งธ ์ฒ ํ: ํ์ ์ธํฐํ์ด์ค ๋์์ธ์ผ๋ก์์ ABC (๋ช ๋ชฉ ํ์ดํ)
ABC๋ฅผ ์ฌ์ฉํ๋ ์ฒซ ๋ฒ์งธ์ด์ ๊ฐ์ฅ ์ ํต์ ์ธ ๋ฐฉ๋ฒ์ ํ์ ์ธํฐํ์ด์ค ๋์์ธ์
๋๋ค. ์ด ์ ๊ทผ ๋ฐฉ์์ Java, C++, C#์ ๊ฐ์ ์ธ์ด์ ๊ฐ๋ฐ์์๊ฒ ์ต์ํ ๋ช
๋ชฉ ํ์ดํ์ด๋ผ๋ ๊ฐ๋
์ ๋ฟ๋ฆฌ๋ฅผ ๋๊ณ ์์ต๋๋ค. ๋ช
๋ชฉ ์์คํ
์์ ์ ํ์ ํธํ์ฑ์ ์ด๋ฆ๊ณผ ๋ช
์์ ์ ์ธ์ ์ํด ๊ฒฐ์ ๋ฉ๋๋ค. ์ด ๋งฅ๋ฝ์์ ํด๋์ค๋ MediaFile
ABC๋ฅผ ๋ช
์์ ์ผ๋ก ์์ํ๋ ๊ฒฝ์ฐ์๋ง MediaFile
๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์ ๋ฌธ๊ฐ ์ธ์ฆ๊ณผ ๊ฐ๋ค๊ณ ์๊ฐํ์ญ์์ค. ๊ณต์ธ ํ๋ก์ ํธ ๊ด๋ฆฌ์๊ฐ ๋๋ ค๋ฉด ๋จ์ํ ๊ทธ๋ ๊ฒ ํ๋ํ๋ ๊ฒ๋ง์ผ๋ก๋ ์ถฉ๋ถํ์ง ์์ต๋๋ค. ํน์ ์ํ์ ํฉ๊ฒฉํ๊ณ ์๊ฒฉ์ด ์์์ ๋ช ์์ ์ผ๋ก ๋ช ์ํ๋ ๊ณต์ ์ธ์ฆ์๋ฅผ ๋ฐ์์ผ ํฉ๋๋ค. ์ธ์ฆ์ ์ด๋ฆ๊ณผ ๊ณ๋ณด๋ ์ค์ํฉ๋๋ค.
์ด ๋ชจ๋ธ์์ ABC๋ ํ์ ๋ถ๊ฐ๋ฅํ ๊ณ์ฝ ์ญํ ์ ํฉ๋๋ค. ์ด๋ฅผ ์์ํจ์ผ๋ก์จ ํด๋์ค๋ ํ์ํ ๊ธฐ๋ฅ์ ์ ๊ณตํ๊ฒ ๋ค๋ ๊ณต์์ ์ธ ์ฝ์์ ์์คํ ์ ๋๋จธ์ง ๋ถ๋ถ์ ํฉ๋๋ค.
์์ : ๋ฐ์ดํฐ ๋ด๋ณด๋ด๊ธฐ ํ๋ ์์ํฌ
๋ค์ํ ํ์์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ด๋ณด๋ผ ์ ์๋ ํ๋ ์์ํฌ๋ฅผ ๊ตฌ์ถํ๋ค๊ณ ๊ฐ์ ํด ๋ด
์๋ค. ๋ชจ๋ ๋ด๋ณด๋ด๊ธฐ ํ๋ฌ๊ทธ์ธ์ด ์๊ฒฉํ ๊ตฌ์กฐ๋ฅผ ์ค์ํ๋๋ก ํ๋ ค๋ฉด DataExporter
์ธํฐํ์ด์ค๋ฅผ ์ ์ํ ์ ์์ต๋๋ค.
import abc
from datetime import datetime
class DataExporter(abc.ABC):
"""A formal interface for data exporting classes."""
@abc.abstractmethod
def export(self, data: list[dict]) -> str:
"""Exports data and returns a status message."""
pass
def get_timestamp(self) -> str:
"""A concrete helper method shared by all subclasses."""
return datetime.utcnow().isoformat()
class CSVExporter(DataExporter):
def export(self, data: list[dict]) -> str:
filename = f"export_{self.get_timestamp()}.csv"
print(f"Exporting {len(data)} rows to {filename}")
# ... actual CSV writing logic ...
return f"Successfully exported to {filename}"
class JSONExporter(DataExporter):
def export(self, data: list[dict]) -> str:
filename = f"export_{self.get_timestamp()}.json"
print(f"Exporting {len(data)} records to {filename}")
# ... actual JSON writing logic ...
return f"Successfully exported to {filename}"
์ฌ๊ธฐ์ CSVExporter
์ JSONExporter
๋ ๋ช
์์ ์ผ๋ก ๊ทธ๋ฆฌ๊ณ ๊ฒ์ฆ ๊ฐ๋ฅํ๊ฒ DataExporter
์
๋๋ค. ์ ํ๋ฆฌ์ผ์ด์
์ ํต์ฌ ๋ก์ง์ ์ด ๊ณ์ฝ์ ์์ ํ๊ฒ ์์กดํ ์ ์์ต๋๋ค.
def run_export_process(exporter: DataExporter, data_to_export: list[dict]):
print("--- Starting export process ---")
if not isinstance(exporter, DataExporter):
raise TypeError("Exporter must be a valid DataExporter implementation.")
status = exporter.export(data_to_export)
print(f"Process finished with status: {status}")
# Usage
data = [{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}]
run_export_process(CSVExporter(), data)
run_export_process(JSONExporter(), data)
ABC๋ ๋ํ get_timestamp()
๋ผ๋ ๊ตฌ์ฒด์ ์ธ ๋ฉ์๋๋ฅผ ์ ๊ณตํ๋ฉฐ, ์ด๋ ๋ชจ๋ ํ์ ํด๋์ค์ ๊ณต์ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค. ์ด๊ฒ์ ์ธํฐํ์ด์ค ๊ธฐ๋ฐ ๋์์ธ์์ ํํ๊ณ ๊ฐ๋ ฅํ ํจํด์
๋๋ค.
ํ์ ์ธํฐํ์ด์ค ์ ๊ทผ ๋ฐฉ์์ ์ฅ๋จ์
์ฅ์ :
- ๋ช
ํํ๊ณ ๋ช
์์ : ๊ณ์ฝ์ด ๋งค์ฐ ๋ช
ํํฉ๋๋ค. ๊ฐ๋ฐ์๋ ์์ ๋ผ์ธ
class CSVExporter(DataExporter):
๋ฅผ ๋ณด๊ณ ํด๋์ค์ ์ญํ ๊ณผ ๊ธฐ๋ฅ์ ์ฆ์ ์ดํดํ ์ ์์ต๋๋ค. - ๋๊ตฌ ์นํ์ : IDE, ๋ฆฐํฐ ๋ฐ ์ ์ ๋ถ์ ๋๊ตฌ๋ ๊ณ์ฝ์ ์ฝ๊ฒ ํ์ธํ ์ ์์ด ํ๋ฅญํ ์๋ ์์ฑ ๋ฐ ์ค๋ฅ ๊ฒ์ฌ๋ฅผ ์ ๊ณตํฉ๋๋ค.
- ๊ณต์ ๊ธฐ๋ฅ: ABC๋ ๊ตฌ์ฒด์ ์ธ ๋ฉ์๋๋ฅผ ์ ๊ณตํ์ฌ ์ค์ ๊ธฐ๋ณธ ํด๋์ค ์ญํ ์ ํ๊ณ ์ฝ๋ ์ค๋ณต์ ์ค์ผ ์ ์์ต๋๋ค.
- ์น์ํจ: ์ด ํจํด์ ๋๋ถ๋ถ์ ๋ค๋ฅธ ๊ฐ์ฒด ์งํฅ ์ธ์ด์ ๊ฐ๋ฐ์์๊ฒ ์ฆ์ ์ธ์๋ฉ๋๋ค.
๋จ์ :
- ๊ฐํ ๊ฒฐํฉ: ๊ตฌ์ฒด์ ์ธ ํด๋์ค๋ ์ด์ ABC์ ์ง์ ์ ์ผ๋ก ์ฐ๊ฒฐ๋ฉ๋๋ค. ABC๋ฅผ ์ด๋ํ๊ฑฐ๋ ๋ณ๊ฒฝํด์ผ ํ๋ ๊ฒฝ์ฐ ๋ชจ๋ ํ์ ํด๋์ค์ ์ํฅ์ ๋ฏธ์นฉ๋๋ค.
- ๊ฒฌ๊ณ ์ฑ ๋ถ์กฑ: ์๊ฒฉํ ๊ณ์ธต์ ๊ด๊ณ๋ฅผ ๊ฐ์ ํฉ๋๋ค. ๋ ผ๋ฆฌ์ ์ผ๋ก ๋ด๋ณด๋ด๊ธฐ ์ญํ ์ ํ ์ ์์ง๋ง ์ด๋ฏธ ๋ค๋ฅธ ํ์ ๊ธฐ๋ณธ ํด๋์ค๋ฅผ ์์ํ๋ ํด๋์ค๊ฐ ์๋ค๋ฉด ์ด๋ป๊ฒ ๋ ๊น์? Python์ ๋ค์ค ์์์ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์ง๋ง ์์ฒด์ ์ธ ๋ณต์ก์ฑ(์: ๋ค์ด์๋ชฌ๋ ๋ฌธ์ )์ ์ด๋ํ ์๋ ์์ต๋๋ค.
- ์นจ์ต์ฑ: ํ์ฌ ์ฝ๋๋ฅผ ์ ์ฉํ๋ ๋ฐ ์ฌ์ฉํ ์ ์์ต๋๋ค.
export()
๋ฉ์๋๊ฐ ์๋ ํด๋์ค๋ฅผ ์ ๊ณตํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ, (๋ถ๊ฐ๋ฅํ๊ฑฐ๋ ๋ฐ๋์งํ์ง ์์ ์ ์๋) ํด๋น ํด๋์ค๋ฅผ ์์ํ์ง ์๊ณ ์๋DataExporter
๋ก ๋ง๋ค ์ ์์ต๋๋ค.
๋ ๋ฒ์งธ ์ฒ ํ: ํ๋กํ ์ฝ ๊ตฌํ์ผ๋ก์์ ABC (๊ตฌ์กฐ์ ํ์ดํ)
๋ ๋ฒ์งธ, ๋ "Pythonic"ํ ์ฒ ํ์ ๋ ํ์ดํ๊ณผ ์ผ์นํฉ๋๋ค. ์ด ์ ๊ทผ ๋ฐฉ์์ ๊ตฌ์กฐ์ ํ์ดํ์ ์ฌ์ฉํ๋ฉฐ, ์ฌ๊ธฐ์ ํธํ์ฑ์ ์ด๋ฆ์ด๋ ๊ณ๋ณด๊ฐ ์๋๋ผ ๊ตฌ์กฐ์ ๋์์ ์ํด ๊ฒฐ์ ๋ฉ๋๋ค. ๊ฐ์ฒด๊ฐ ์์ ์ ์ํํ๋ ๋ฐ ํ์ํ ๋ฉ์๋์ ์์ฑ์ ๊ฐ์ง๊ณ ์๋ค๋ฉด, ์ ์ธ๋ ํด๋์ค ๊ณ์ธต ๊ตฌ์กฐ์ ๊ด๊ณ์์ด ํด๋น ์์ ์ ์ ํฉํ ์ ํ์ผ๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์์ํ ์ ์๋ ๋ฅ๋ ฅ์ ์๊ฐํด ๋ณด์ธ์. ์์์ ์๋ก ๊ฐ์ฃผ๋๊ธฐ ์ํด ์ธ์ฆ์๊ฐ ํ์ํ๊ฑฐ๋ "์์์ ์" ๊ณ๋ณด์ ์ํ ํ์๋ ์์ต๋๋ค. ๋ฌผ์ ์ต์ฌํ์ง ์๊ณ ์ค์ค๋ก ์ถ์งํ ์ ์๋ค๋ฉด ๊ตฌ์กฐ์ ์ผ๋ก ์์์ ์์ ๋๋ค. ์ฌ๋, ๊ฐ, ์ค๋ฆฌ ๋ชจ๋ ์์์ ์๊ฐ ๋ ์ ์์ต๋๋ค.
ABC๋ ์ด ๊ฐ๋
์ ํ์ํํ๋ ๋ฐ ์ฌ์ฉ๋ ์ ์์ต๋๋ค. ์์์ ๊ฐ์ ํ๋ ๋์ , ๋ค๋ฅธ ํด๋์ค๋ฅผ ํด๋น ํด๋์ค์ ๊ฐ์ ํ์ ํด๋์ค๋ก ์ธ์ํ๋ ABC๋ฅผ ์ ์ํ ์ ์์ผ๋ฉฐ, ์ด๋ ํ์ ํ๋กํ ์ฝ์ ๊ตฌํํ๋ ๊ฒฝ์ฐ์๋ง ๊ฐ๋ฅํฉ๋๋ค. ์ด๋ ํน์ ๋ง๋ฒ ๋ฉ์๋์ธ __subclasshook__
์ ํตํด ๋ฌ์ฑ๋ฉ๋๋ค.
isinstance(obj, MyABC)
๋๋ issubclass(SomeClass, MyABC)
๋ฅผ ํธ์ถํ ๋ Python์ ๋จผ์ ๋ช
์์ ์์์ ํ์ธํฉ๋๋ค. ์คํจํ๋ฉด MyABC
์ __subclasshook__
๋ฉ์๋๊ฐ ์๋์ง ํ์ธํฉ๋๋ค. ๊ทธ๋ ๋ค๋ฉด Python์ ์ด๋ฅผ ํธ์ถํ์ฌ "์ด ํด๋์ค๋ฅผ ๊ทํ์ ํ์ ํด๋์ค๋ก ๊ฐ์ฃผํฉ๋๊น?"๋ผ๊ณ ๋ฌป์ต๋๋ค. ์ด๋ฅผ ํตํด ABC๋ ๊ตฌ์กฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋ฉค๋ฒ์ญ ๊ธฐ์ค์ ์ ์ํ ์ ์์ต๋๋ค.
์์ : Serializable
ํ๋กํ ์ฝ
๋์ ๋๋ฆฌ๋ก ์ง๋ ฌํ๋ ์ ์๋ ๊ฐ์ฒด์ ๋ํ ํ๋กํ ์ฝ์ ์ ์ํด ๋ด ์๋ค. ์์คํ ์ ๋ชจ๋ ์ง๋ ฌํ ๊ฐ๋ฅํ ๊ฐ์ฒด๊ฐ ๊ณตํต ๊ธฐ๋ณธ ํด๋์ค๋ฅผ ์์ํ๋๋ก ๊ฐ์ ํ๊ณ ์ถ์ง๋ ์์ต๋๋ค. ํด๋น ๊ฐ์ฒด๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ชจ๋ธ, ๋ฐ์ดํฐ ์ ์ก ๊ฐ์ฒด ๋๋ ๊ฐ๋จํ ์ปจํ ์ด๋์ผ ์ ์์ต๋๋ค.
import abc
class Serializable(abc.ABC):
@abc.abstractmethod
def to_dict(self) -> dict:
pass
@classmethod
def __subclasshook__(cls, C):
if cls is Serializable:
# 'to_dict'๊ฐ C์ ๋ฉ์๋ ํด์ ์์์ ์๋์ง ํ์ธ
if any("to_dict" in B.__dict__ for B in C.__mro__):
return True
return NotImplemented
์ด์ ๋ช ๊ฐ์ง ํด๋์ค๋ฅผ ๋ง๋ค์ด ๋ด
์๋ค. ์ค์ํ ๊ฒ์ ์ด๋ค ์ค ์ด๋ ๊ฒ๋ Serializable
์ ์์ํ์ง ์๋๋ค๋ ๊ฒ์
๋๋ค.
class User:
def __init__(self, name: str, email: str):
self.name = name
self.email = email
def to_dict(self) -> dict:
return {"name": self.name, "email": self.email}
class Product:
def __init__(self, sku: str, price: float):
self.sku = sku
self.price = price
# ์ด ํด๋์ค๋ ํ๋กํ ์ฝ์ ์ค์ํ์ง ์์ต๋๋ค.
class Configuration:
def __init__(self, setting: str):
self.setting = setting
ํ๋กํ ์ฝ์ ๋ํด ํ์ธํด ๋ด ์๋ค.
print(f"Is User serializable? {isinstance(User('Test', 't@t.com'), Serializable)}")
print(f"Is Product serializable? {isinstance(Product('T-1000', 99.99), Serializable)}")
print(f"Is Configuration serializable? {isinstance(Configuration('ON'), Serializable)}")
# ์ถ๋ ฅ:
# Is User serializable? True
# Is Product serializable? False <- ์ ๊ทธ๋ด๊น์? ์์ ํด ๋ด
์๋ค.
# Is Configuration serializable? False
์, ํฅ๋ฏธ๋ก์ด ๋ฒ๊ทธ์
๋๋ค! Product
ํด๋์ค์๋ to_dict
๋ฉ์๋๊ฐ ์์ต๋๋ค. ์ถ๊ฐํด ๋ด
์๋ค.
class Product:
def __init__(self, sku: str, price: float):
self.sku = sku
self.price = price
def to_dict(self) -> dict: # ๋ฉ์๋ ์ถ๊ฐ
return {"sku": self.sku, "price": self.price}
print(f"Is Product now serializable? {isinstance(Product('T-1000', 99.99), Serializable)}")
# ์ถ๋ ฅ:
# Is Product now serializable? True
User
์ Product
๋ ๊ณตํต ๋ถ๋ชจ ํด๋์ค(object
์ธ)๋ฅผ ๊ณต์ ํ์ง ์๋๋ผ๋, ์ด ๋ ๋ชจ๋ Serializable
๋ก ์ทจ๊ธ๋ ์ ์์ต๋๋ค. ์๋ํ๋ฉด ์ด๋ค์ด ํ๋กํ ์ฝ์ ์ถฉ์กฑํ๊ธฐ ๋๋ฌธ์
๋๋ค. ์ด๋ ๋งค์ฐ ๊ฐ๋ ฅํ ๋์ปคํ๋ง ๋๊ตฌ์
๋๋ค.
ํ๋กํ ์ฝ ์ ๊ทผ ๋ฐฉ์์ ์ฅ๋จ์
์ฅ์ :
- ์ต๋ ์ ์ฐ์ฑ: ๋งค์ฐ ๋์จํ ๊ฒฐํฉ์ ์ด์งํฉ๋๋ค. ๊ตฌ์ฑ ์์๋ ๊ตฌํ ๊ณ๋ณด๊ฐ ์๋ ๋์์๋ง ์ ๊ฒฝ ์๋๋ค.
- ์ ์์ฑ: ๊ธฐ์กด ์ฝ๋๋ฅผ ์์ ํ์ง ์๊ณ ์์คํ ์ ์ธํฐํ์ด์ค์ ๋ง์ถ๊ธฐ ์ํด, ํนํ ํ์ฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ฝ๋๋ฅผ ์ ์์ํค๋ ๋ฐ ์๋ฒฝํฉ๋๋ค.
- ๊ตฌ์ฑ ์ด์ง: ๊น๊ณ ๊ฒฌ๊ณ ํ ์์ ํธ๋ฆฌ๋ณด๋ค๋ ๋ ๋ฆฝ์ ์ธ ๊ธฐ๋ฅ์ผ๋ก ๊ตฌ์ถ๋ ๊ฐ์ฒด๋ก ๊ตฌ์ฑํ๋ ์คํ์ผ์ ์ฅ๋ คํฉ๋๋ค.
๋จ์ :
- ์๋ฌต์ ๊ณ์ฝ: ํด๋์ค์ ํด๋น ํด๋์ค๊ฐ ๊ตฌํํ๋ ํ๋กํ ์ฝ ๊ฐ์ ๊ด๊ณ๋ ํด๋์ค ์ ์์์ ์ฆ์ ๋ช
ํํ์ง ์์ต๋๋ค. ๊ฐ๋ฐ์๋
User
๊ฐ์ฒด๊ฐSerializable
๋ก ์ทจ๊ธ๋๋ ์ด์ ๋ฅผ ์ดํดํ๊ธฐ ์ํด ์ฝ๋๋ฒ ์ด์ค๋ฅผ ๊ฒ์ํด์ผ ํ ์ ์์ต๋๋ค. - ๋ฐํ์ ์ค๋ฒํค๋:
isinstance
๊ฒ์ฌ๋__subclasshook__
์ ํธ์ถํ๊ณ ํด๋์ค์ ๋ฉ์๋์ ๋ํ ๊ฒ์ฌ๋ฅผ ์ํํด์ผ ํ๋ฏ๋ก ๋ ๋๋ฆด ์ ์์ต๋๋ค. - ๋ณต์ก์ฑ ๊ฐ๋ฅ์ฑ:
__subclasshook__
๋ด๋ถ์ ๋ก์ง์ ํ๋กํ ์ฝ์ด ์ฌ๋ฌ ๋ฉ์๋, ์ธ์ ๋๋ ๋ฐํ ์ ํ์ ํฌํจํ๋ ๊ฒฝ์ฐ ๋งค์ฐ ๋ณต์กํด์ง ์ ์์ต๋๋ค.
ํ๋์ ์ข
ํฉ: typing.Protocol
๋ฐ ์ ์ ๋ถ์
Python์ด ๋๊ท๋ชจ ์์คํ
์์ ์ฌ์ฉ๋๋ ๊ฒ์ด ์ฆ๊ฐํจ์ ๋ฐ๋ผ ๋ ๋์ ์ ์ ๋ถ์์ ๋ํ ์ด๋ง๋ ์ปค์ก์ต๋๋ค. __subclasshook__
์ ๊ทผ ๋ฐฉ์์ ๊ฐ๋ ฅํ์ง๋ง ์์ ํ ๋ฐํ์ ๋ฉ์ปค๋์ฆ์
๋๋ค. ์ฝ๋๋ฅผ ์คํํ๊ธฐ๋ ์ ์ ๊ตฌ์กฐ์ ํ์ดํ์ ์ด์ ์ ์ป์ ์ ์๋ค๋ฉด ์ด๋จ๊น์?
์ด๊ฒ์ด PEP 544์์ `typing.Protocol`์ด ๋์ ๋ ์ด์ ์ ๋๋ค. ์ด๋ ์ฃผ๋ก Mypy, Pyright ๋๋ PyCharm์ ๊ฒ์ฌ๊ธฐ ๋ฑ ์ ์ ํ์ ๊ฒ์ฌ๋ฅผ ์ํ ํ๋กํ ์ฝ์ ์ ์ํ๋ ํ์คํ๋๊ณ ์ฐ์ํ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค.
Protocol
ํด๋์ค๋ __subclasshook__
์์ ์ ์ ์ฌํ๊ฒ ์๋ํ์ง๋ง ์์ฉ๊ตฌ ์ฝ๋๊ฐ ์์ต๋๋ค. ๋จ์ํ ๋ฉ์๋์ ํด๋น ์๊ทธ๋์ฒ๋ฅผ ์ ์ํ๋ฉด ๋ฉ๋๋ค. ์ผ์นํ๋ ๋ฉ์๋์ ์๊ทธ๋์ฒ๋ฅผ ๊ฐ์ง ๋ชจ๋ ํด๋์ค๋ ์ ์ ํ์
๊ฒ์ฌ๊ธฐ์ ์ํด ๊ตฌ์กฐ์ ์ผ๋ก ํธํ๋๋ ๊ฒ์ผ๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์์ : Quacker
ํ๋กํ ์ฝ
ํ๋์ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ฌ ๊ณ ์ ์ ์ธ ๋ ํ์ดํ ์์ ๋ฅผ ๋ค์ ์ดํด๋ด ์๋ค.
from typing import Protocol
class Quacker(Protocol):
def quack(self, volume: int) -> str:
"""Produces a quacking sound."""
... # ์ฐธ๊ณ : ํ๋กํ ์ฝ ๋ฉ์๋์ ๋ณธ๋ฌธ์ ํ์ํ์ง ์์ต๋๋ค.
class Duck:
def quack(self, volume: int) -> str:
return f"QUACK! (at volume {volume})"
class Dog:
def bark(self, volume: int) -> str:
return f"WOOF! (at volume {volume})"
def make_sound(animal: Quacker):
print(animal.quack(10))
make_sound(Duck()) # ์ ์ ๋ถ์ ํต๊ณผ
make_sound(Dog()) # ์ ์ ๋ถ์ ์คํจ!
์ด ์ฝ๋๋ฅผ Mypy์ ๊ฐ์ ํ์
๊ฒ์ฌ๊ธฐ๋ก ์คํํ๋ฉด `make_sound(Dog())` ์ค์ ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค. Argument 1 to "make_sound" has incompatible type "Dog"; expected "Quacker"
. ํ์
๊ฒ์ฌ๊ธฐ๋ Dog
์ quack
๋ฉ์๋๊ฐ ์๊ธฐ ๋๋ฌธ์ Quacker
ํ๋กํ ์ฝ์ ์ถฉ์กฑํ์ง ๋ชปํ๋ค๋ ๊ฒ์ ์ดํดํฉ๋๋ค. ์ด๊ฒ์ ์ฝ๋๊ฐ ์คํ๋๊ธฐ ์ ์ ์ค๋ฅ๋ฅผ ํฌ์ฐฉํฉ๋๋ค.
`@runtime_checkable`์ ์ฌ์ฉํ ๋ฐํ์ ํ๋กํ ์ฝ
๊ธฐ๋ณธ์ ์ผ๋ก typing.Protocol
์ ์ ์ ๋ถ์๋ง์ ์ํ ๊ฒ์
๋๋ค. ๋ฐํ์ isinstance
๊ฒ์ฌ์ ์ฌ์ฉํ๋ ค๊ณ ํ๋ฉด ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.
# isinstance(Duck(), Quacker) # -> TypeError: Protocol 'Quacker' cannot be instantiated
๊ทธ๋ฌ๋ `@runtime_checkable` ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํ์ฌ ์ ์ ๋ถ์๊ณผ ๋ฐํ์ ๋์ ๊ฐ์ ๊ฒฉ์ฐจ๋ฅผ ํด์ํ ์ ์์ต๋๋ค. ์ด๋ ์ค์ ๋ก Python์๊ฒ ์๋์ผ๋ก __subclasshook__
๋ก์ง์ ์์ฑํ๋๋ก ์ง์ํ๋ ๊ฒ๊ณผ ๊ฐ์ต๋๋ค.
from typing import Protocol, runtime_checkable
@runtime_checkable
class Quacker(Protocol):
def quack(self, volume: int) -> str: ...
class Duck:
def quack(self, volume: int) -> str: return "..."
print(f"Is Duck an instance of Quacker? {isinstance(Duck(), Quacker)}")
# ์ถ๋ ฅ:
# Is Duck an instance of Quacker? True
์ด๋ฅผ ํตํด ๋ ๊ฐ์ง ์ฅ์ ์ ๋ชจ๋ ์ป์ ์ ์์ต๋๋ค. ์ ์ ๋ถ์์ ์ํ ๊น๋ํ๊ณ ์ ์ธ์ ์ธ ํ๋กํ ์ฝ ์ ์์ ํ์ํ ๋ ๋ฐํ์ ์ ํจ์ฑ ๊ฒ์ฌ ์ต์
. ๊ทธ๋ฌ๋ ํ๋กํ ์ฝ์ ๋ํ ๋ฐํ์ ๊ฒ์ฌ๋ ํ์ค isinstance
ํธ์ถ๋ณด๋ค ๋๋ฆฌ๋ค๋ ์ ์ ์ ์ํด์ผ ํ๋ฏ๋ก ์ ์คํ๊ฒ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
์ค์ฉ์ ์ธ ์์ฌ ๊ฒฐ์ : ๊ธ๋ก๋ฒ ๊ฐ๋ฐ์๋ฅผ ์ํ ๊ฐ์ด๋
๊ทธ๋ ๋ค๋ฉด ์ด๋ค ์ ๊ทผ ๋ฐฉ์์ ์ ํํด์ผ ํ ๊น์? ๋ต์ ์ ์ ์ผ๋ก ํน์ ์ฌ์ฉ ์ฌ๋ก์ ๋ฌ๋ ค ์์ต๋๋ค. ๋ค์์ ๊ตญ์ ์ํํธ์จ์ด ํ๋ก์ ํธ์ ์ผ๋ฐ์ ์ธ ์๋๋ฆฌ์ค๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ ์ค์ฉ์ ์ธ ๊ฐ์ด๋์ ๋๋ค.
์๋๋ฆฌ์ค 1: ๊ธ๋ก๋ฒ SaaS ์ ํ์ ์ํ ํ๋ฌ๊ทธ์ธ ์ํคํ ์ฒ ๊ตฌ์ถ
์ ์ธ๊ณ์ 1์ฐจ ๋ฐ 3์ฐจ ๊ฐ๋ฐ์๊ฐ ํ์ฅํ ์์คํ (์: ์ ์ ์๊ฑฐ๋ ํ๋ซํผ, CMS)์ ์ค๊ณํ๊ณ ์์ต๋๋ค. ์ด๋ฌํ ํ๋ฌ๊ทธ์ธ์ ํต์ฌ ์ ํ๋ฆฌ์ผ์ด์ ๊ณผ ๊น์ด ํตํฉ๋์ด์ผ ํฉ๋๋ค.
- ๊ถ์ฅ ์ฌํญ: ํ์ ์ธํฐํ์ด์ค (๋ช ๋ชฉ `abc.ABC`).
- ์ด์ : ๋ช
ํ์ฑ, ์์ ์ฑ ๋ฐ ๋ช
์์ฑ์ด ๊ฐ์ฅ ์ค์ํฉ๋๋ค. ์ ์ธ๊ณ ํ๋ฌ๊ทธ์ธ ๊ฐ๋ฐ์๊ฐ
BasePlugin
ABC๋ฅผ ์์ํ๋๋ก ์๋์ ์ผ๋ก ์ ํํด์ผ ํ๋ ๋นํ์ ๊ณ์ฝ์ด ํ์ํฉ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด API๊ฐ ๋ชจํธํด์ง์ง ์์ต๋๋ค. ๋ํ ๊ธฐ๋ณธ ํด๋์ค์ ํ์์ ์ธ ๋์ฐ๋ฏธ ๋ฉ์๋(์: ๋ก๊น , ๊ตฌ์ฑ ์ก์ธ์ค, ๊ตญ์ ํ)๋ฅผ ์ ๊ณตํ ์ ์์ผ๋ฉฐ, ์ด๋ ๊ฐ๋ฐ์ ์ํ๊ณ์ ํฐ ์ด์ ์ ๋๋ค.
์๋๋ฆฌ์ค 2: ์ฌ๋ฌ ๊ด๋ จ ์๋ API์ ๊ธ์ต ๋ฐ์ดํฐ ์ฒ๋ฆฌ
๊ท์ฌ์ ํํ ํฌ ์ ํ๋ฆฌ์ผ์ด์ ์ Stripe, PayPal, Adyen ๋ฐ ๋ผํด ์๋ฉ๋ฆฌ์นด์ Mercado Pago์ ๊ฐ์ ์ง์ญ ์ ๊ณต์ ์ฒด์ ๊ฐ์ ๋ค์ํ ๊ธ๋ก๋ฒ ๊ฒฐ์ ๊ฒ์ดํธ์จ์ด์์ ๊ฑฐ๋ ๋ฐ์ดํฐ๋ฅผ ์๋นํด์ผ ํฉ๋๋ค. ํด๋น SDK์์ ๋ฐํ๋๋ ๊ฐ์ฒด๋ ์์ ํ ๊ทํ์ ํต์ ๋ฐ์ ์์ต๋๋ค.
- ๊ถ์ฅ ์ฌํญ: ํ๋กํ ์ฝ (`typing.Protocol`).
- ์ด์ : ์ด๋ฌํ ํ์ฌ SDK์ ์์ค ์ฝ๋๋ฅผ ์์ ํ์ฌ
Transaction
๊ธฐ๋ณธ ํด๋์ค๋ฅผ ์์ํ๋๋ก ๋ง๋ค ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ํด๋น ๊ฑฐ๋ ๊ฐ์ฒด๊ฐget_id()
,get_amount()
,get_currency()
์ ๊ฐ์ ๋ฉ์๋๋ฅผ ๊ฐ์ง๊ณ ์๋ค๋ ๊ฒ์ ์๊ณ ์์ต๋๋ค.TransactionProtocol
๊ณผ ํจ๊ป ์ด๋ํฐ ํจํด์ ์ฌ์ฉํ์ฌ ํต์ผ๋ ๋ณด๊ธฐ๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค. ํ๋กํ ์ฝ์ ์ฌ์ฉํ๋ฉด ํ์ํ ๋ฐ์ดํฐ์ *๋ชจ์*์ ์ ์ํ ์ ์์ผ๋ฏ๋ก, ํ๋กํ ์ฝ์ ๋ง๊ฒ ์กฐ์ ํ ์๋ง ์๋ค๋ฉด ์ด๋ค ๋ฐ์ดํฐ ์์ค์๋ ์๋ํ๋ ์ฒ๋ฆฌ ๋ก์ง์ ์์ฑํ ์ ์์ต๋๋ค.
์๋๋ฆฌ์ค 3: ๋๊ท๋ชจ, ๋ชจ๋๋ฆฌ์ ๋ ๊ฑฐ์ ์ ํ๋ฆฌ์ผ์ด์ ๋ฆฌํฉํ ๋ง
๋ ๊ฑฐ์ ๋ชจ๋๋ฆฌ์ค๋ฅผ ์ต์ ๋ง์ดํฌ๋ก ์๋น์ค๋ก ๋ถํดํ๋ ์์ ์ ๋งก์์ต๋๋ค. ๊ธฐ์กด ์ฝ๋๋ฒ ์ด์ค๋ ์ข ์์ฑ์ ๋ณต์กํ ์น์ด๋ฉฐ, ๋ชจ๋ ๊ฒ์ ํ ๋ฒ์ ๋ค์ ์์ฑํ์ง ์๊ณ ๋ช ํํ ๊ฒฝ๊ณ๋ฅผ ๋์ ํด์ผ ํฉ๋๋ค.
- ๊ถ์ฅ ์ฌํญ: ํผํฉ, ๊ทธ๋ฌ๋ ํ๋กํ ์ฝ์ ํฌ๊ฒ ์์กด.
- ์ด์ : ํ๋กํ ์ฝ์ ์ ์ง์ ๋ฆฌํฉํ ๋ง์ ํ์ํ ๋๊ตฌ์
๋๋ค. ๋จผ์
typing.Protocol
์ ์ฌ์ฉํ์ฌ ์ ์๋น์ค ๊ฐ์ ์ด์์ ์ธ ์ธํฐํ์ด์ค๋ฅผ ์ ์ํ ์ ์์ต๋๋ค. ๊ทธ๋ฐ ๋ค์ ๊ธฐ์กด ํต์ฌ ์ฝ๋๋ฅผ ์ฆ์ ๋ณ๊ฒฝํ์ง ์๊ณ ์ด๋ฌํ ํ๋กํ ์ฝ์ ์ค์ํ๋๋ก ๋ชจ๋๋ฆฌ์ค์ ์ผ๋ถ์ ๋ํ ์ด๋ํฐ๋ฅผ ์์ฑํ ์ ์์ต๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ๊ตฌ์ฑ ์์๋ฅผ ์ ์ง์ ์ผ๋ก ๋์ปคํ๋งํ ์ ์์ต๋๋ค. ๊ตฌ์ฑ ์์๊ฐ ์์ ํ ๋์ปคํ๋ง๋๊ณ ํ๋กํ ์ฝ์ ํตํด์๋ง ํต์ ํ๋ฉด ์์ฒด ์๋น์ค๋ก ์ถ์ถํ ์ค๋น๊ฐ ๋ ๊ฒ์ ๋๋ค. ํ์ ABC๋ ๋์ค์ ์๋ก์ด ๊น๋ํ ์๋น์ค ๋ด์ ํต์ฌ ๋ชจ๋ธ์ ์ ์ํ๋ ๋ฐ ์ฌ์ฉ๋ ์ ์์ต๋๋ค.
๊ฒฐ๋ก : ์ถ์ํ๋ฅผ ์ฝ๋๋ก ์ฎ๊ธฐ
Python์ ์ถ์ ๊ธฐ๋ณธ ํด๋์ค๋ Python์ ์ค์ฉ์ ์ธ ๋์์ธ์ ๋ํ ์ฆ๊ฑฐ์ ๋๋ค. ์ด๋ ์ ํต์ ์ธ ๊ฐ์ฒด ์งํฅ ํ๋ก๊ทธ๋๋ฐ์ ๊ตฌ์กฐํ๋ ๊ท์จ๊ณผ ๋ ํ์ดํ์ ๋์ ์ ์ฐ์ฑ์ ๋ชจ๋ ์กด์คํ๋ ์ ๊ตํ ์ถ์ํ ๋๊ตฌ ์ธํธ๋ฅผ ์ ๊ณตํฉ๋๋ค.
์๋ฌต์ ๊ณ์ฝ์์ ํ์ ๊ณ์ฝ์ผ๋ก์ ์ฌ์ ์ ์ฝ๋๋ฒ ์ด์ค๊ฐ ์ฑ์ํ์์ ๋ํ๋ด๋ ์ ํธ์ ๋๋ค. ABC์ ๋ ๊ฐ์ง ์ฒ ํ์ ์ดํดํจ์ผ๋ก์จ ๋ ๊น๋ํ๊ณ ์ ์ง๋ณด์ ๊ฐ๋ฅํ๋ฉฐ ํ์ฅ ๊ฐ๋ฅํ ์ ํ๋ฆฌ์ผ์ด์ ์ผ๋ก ์ด์ด์ง๋ ์ ๋ณด์ ์ ๊ฐํ ์ํคํ ์ฒ ๊ฒฐ์ ์ ๋ด๋ฆด ์ ์์ต๋๋ค.
์ฃผ์ ๋ด์ฉ์ ์์ฝํ์๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- ํ์ ์ธํฐํ์ด์ค ๋์์ธ (๋ช
๋ชฉ ํ์ดํ): ๋ช
์์ ์ด๊ณ ๋ชจํธํ์ง ์์ผ๋ฉฐ ๊ฒ์ ๊ฐ๋ฅํ ๊ณ์ฝ์ด ํ์ํ ๊ฒฝ์ฐ ์ง์ ์์๊ณผ ํจ๊ป
abc.ABC
๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์ด๋ ํ๋ ์์ํฌ, ํ๋ฌ๊ทธ์ธ ์์คํ ๋ฐ ํด๋์ค ๊ณ์ธต ๊ตฌ์กฐ๋ฅผ ์ ์ดํ๋ ์ํฉ์ ์ด์์ ์ ๋๋ค. ์ ์ธ์ ์ํด ํด๋์ค๊ฐ ๋ฌด์์ธ์ง์ ๊ดํ ๊ฒ์ ๋๋ค. - ํ๋กํ ์ฝ ๊ตฌํ (๊ตฌ์กฐ์ ํ์ดํ): ์ ์ฐ์ฑ, ๋์ปคํ๋ง ๋ฐ ๊ธฐ์กด ์ฝ๋๋ฅผ ์ ์์ํค๋ ๊ธฐ๋ฅ์ด ํ์ํ ๊ฒฝ์ฐ
typing.Protocol
์ ์ฌ์ฉํฉ๋๋ค. ํ์ฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์์ , ๋ ๊ฑฐ์ ์์คํ ๋ฆฌํฉํ ๋ง ๋ฐ ๋์ ๋คํ์ฑ์ ์ํ ์ค๊ณ์ ์๋ฒฝํฉ๋๋ค. ํด๋์ค๊ฐ ๋ฌด์์ ํ ์ ์๋์ง์ ๊ตฌ์กฐ์ ๊ดํ ๊ฒ์ ๋๋ค.
์ธํฐํ์ด์ค์ ํ๋กํ ์ฝ ๊ฐ์ ์ ํ์ ๋จ์ํ ๊ธฐ์ ์ธ๋ถ ์ฌํญ์ด ์๋๋๋ค. ์ํํธ์จ์ด์ ์งํ ๋ฐฉ์์ ํ์ฑํ ๊ทผ๋ณธ์ ์ธ ์ค๊ณ ๊ฒฐ์ ์ ๋๋ค. ๋ ๋ค ์๋ฌํจ์ผ๋ก์จ Python ์ฝ๋๋ฅผ ๊ฐ๋ ฅํ๊ณ ํจ์จ์ ์ผ ๋ฟ๋ง ์๋๋ผ ์ฐ์ํ๊ณ ๋ณํ์ ๋ํ ๋ณต์๋ ฅ ์๊ฒ ์์ฑํ ์ ์์ต๋๋ค.